/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: DOMTest.java,v $
 *
 */

package com.cidero.upnp;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;

import org.cybergarage.xml.XML;

/**
 *
 *  XML parser test
 *  
 */
public class NotifyXMLTest
{
  public NotifyXMLTest()
  {
  }

  public void performDemo( String uri ) {

    System.out.println("Parsing XML file: " + uri + "\n" );

    DOMParser parser = new DOMParser();
    
    String xmlStr = "<e:propertyset  xmlns:e=\"urn:schemas-upnp-org:event-1-0\"><e:property><LastChange><Event  xmlns=\"urn:schemas-upnp-org:metadata-1-0/AVT/\"><InstanceID  val=\"0\"><TransportState  val=\"PLAYING\"/></InstanceID></Event></LastChange></e:property></e:propertyset>";
    

    //
    // Patch for devices that don't properly doubly-escape the 'LastChange'
    // events (nested XML fragment). Philips Streamium SL50i is guilty of this
    //

    // Do a quick check on the front part of the xml to make sure it is 
    // a propertyset (event)
    int testLength = 256;
    if( testLength >= xmlStr.length() )
      testLength = xmlStr.length();
    String testString = xmlStr.substring(0, testLength-1 );

    if( testString.indexOf("propertyset") >= 0 )
    {
      // If last change event, and XML within the LastChange element is not
      // properly escaped, fix it 
      int lastChangeStart = xmlStr.indexOf("<LastChange>");
      int lastChangeEnd = xmlStr.indexOf("</LastChange>");
      if( (lastChangeStart > 0) && (lastChangeEnd > 0) )
      {
        String eventStr = xmlStr.substring(lastChangeStart+12,
                                           lastChangeEnd).trim();

        if( eventStr.startsWith("<Event") )
        {
          // Non-escaped XML in last change value - escape it before 
          // proceeding
          String escapedEventStr = XML.escapeXMLChars( eventStr );

          String tmp = xmlStr.substring(0,lastChangeStart+12) +
          escapedEventStr + xmlStr.substring( lastChangeEnd );
          xmlStr = tmp;

          System.out.println("New xmlStr: " + xmlStr );
        }
      }
    }
    

    byte[] xmlByteArray = xmlStr.getBytes();

    // If this is notify message ('propertyset' string near beginning) and
    // the LastChange content is not properly escaped, do it. 


    ByteArrayInputStream xmlStream = new  ByteArrayInputStream( xmlByteArray );
    //    InputStreamReader xmlReader = new InputStreamReader( xmlStream );

    try 
    {
      parser.parse( new InputSource( xmlStream ) );

      Document doc = parser.getDocument();

      printNode( doc, "" );

      System.out.println("\nDone parsing\n");

      //System.out.println("Converting DOM to CDS\n");
      //DOMToCDS( doc );

    }
    catch( IOException e ) 
    {
      System.out.println("Error reading URI: " + e.getMessage() );
      
    }
    catch( SAXException e ) 
    {
      System.out.println("Error parsing URI: " + e.getMessage() );
      
    }

  }


  public void printNode( Node node, String indent )
  {
    // Determine type of node

    switch( node.getNodeType() )
    {
      case Node.DOCUMENT_NODE:
        System.out.println("<xml version = \"1.0\">\n");
        Document doc = (Document)node;
        printNode( doc.getDocumentElement(), "" );
        break;

      case Node.ELEMENT_NODE:
        String name = node.getNodeName();
        System.out.print( indent + "<" + name );

        NamedNodeMap attributes = node.getAttributes();
        for( int n = 0 ; n < attributes.getLength() ; n++ )
        {
          Node current = attributes.item(n);
          System.out.print( " " + current.getNodeName() +
                            "=\"" + current.getNodeValue() +
                            "\"" );
        }
        
        NodeList children = node.getChildNodes();

        // If simple node, don't bother with newline between tags
        if( (children != null) && (children.getLength() > 0) &&
            (attributes.getLength() > 0 ) )
        {
          System.out.println( ">" );
        }
        else
        {
          System.out.println( ">" );
        }
        

        // Recurse on children

        if( children != null )
        {
          for( int n = 0 ; n < children.getLength() ; n++ )
          {
            printNode( children.item(n), indent + "  " );
          }
        }
        
        if( (children != null) && (children.getLength() > 0) &&
            (attributes.getLength() > 0 ) )
        {
          System.out.println( indent + "</" + name + ">" );
        }
        else
        {
          System.out.println( "</" + name + ">" );
        }

        break;
        
      case Node.TEXT_NODE:
      case Node.CDATA_SECTION_NODE:

        System.out.print( "("+ node.getNodeValue() + ")" );
        break;

      case Node.PROCESSING_INSTRUCTION_NODE:
        
        break;

      case Node.ENTITY_REFERENCE_NODE:
        
        break;

      case Node.DOCUMENT_TYPE_NODE:
        
        break;


    }

  }
  

  public static void main( String[] args )
  {
    if( args.length != 1 )
    {
      System.out.println("Usage: java DOMTest <XML file>" );
      System.exit(0);
    }
    
    String uri = args[0];
    
    NotifyXMLTest notifyXMLTest = new NotifyXMLTest();

    notifyXMLTest.performDemo( uri );
    
  }


}
